package com.ioudi.digu.service.impl;

import java.lang.reflect.Method;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.jws.WebService;

import org.springframework.security.providers.UsernamePasswordAuthenticationToken;

import com.ioudi.digu.annotation.TypeDefination;
import com.ioudi.digu.dao.UserDAO;
import com.ioudi.digu.dsdistribute.IDatasourceDistribute;
import com.ioudi.digu.dsdistribute.method.MethodInfo;
import com.ioudi.digu.security.userdetails.UserDetails;
import com.ioudi.digu.service.IFriendshipService;
import com.ioudi.digu.service.IReceivedService;
import com.ioudi.digu.service.IUserService;
import com.ioudi.digu.service.drm.DatasourceUserAwareService;
import com.ioudi.digu.service.support.ListResult;
import com.ioudi.digu.util.ArrayUtil;
import com.ioudi.digu.util.ContextUtil;
import com.ioudi.digu.vo.User;
import com.ioudi.digu.vo.adapter.OutboundUser;

import flex.messaging.FlexContext;
import flex.messaging.MessageBroker;
import flex.messaging.client.FlexClient;
import flex.messaging.security.LoginManager;

@WebService (
		  endpointInterface = "com.ioudi.digu.service.IUserService"
		)
public class UserService extends DatasourceUserAwareService implements IUserService
{
	private LoginManager loginManager;
	
	private UserDAO userDAO;
	
	private IReceivedService receivedService;
	
	private String defaultProfileImage;
	
	public String getDefaultProfileImage()
	{
		return defaultProfileImage;
	}

	public void setDefaultProfileImage(String defaultProfileImage)
	{
		this.defaultProfileImage = defaultProfileImage;
	}

	public IReceivedService getReceivedService()
	{
		return receivedService;
	}

	public void setReceivedService(IReceivedService receivedService)
	{
		this.receivedService = receivedService;
	}

	public UserDAO getUserDAO()
	{
		return userDAO;
	}

	public void setUserDAO(UserDAO userDAO)
	{
		this.userDAO = userDAO;
	}

	public LoginManager getLoginManager()
	{
		return loginManager;
	}

	public void setLoginManager(LoginManager loginManager)
	{
		this.loginManager = loginManager;
	}

	public boolean existUser(String account)
	{
		return  getDatasourceDistribute().lookupDatasource(account, false) != null;
	}

	public OutboundUser login(String account, String passwordMD5)
	{
		if(this.getUser() != null)
		{
			return null;
		}
		if(loginManager == null)
		{
			Object temp = ContextUtil.getBeanInFlexContext("_messageBroker");
			if(temp instanceof MessageBroker)
			{
				loginManager = ((MessageBroker)temp).getLoginManager();
			}
		}
		User user = null;
		if(loginManager != null)
		{
			loginManager.login(account, passwordMD5);
			UsernamePasswordAuthenticationToken token = 
				 (UsernamePasswordAuthenticationToken)FlexContext.getUserPrincipal();
			user =  (User)((UserDetails)token.getPrincipal()).getRealUser();
			((UserDetails)token.getPrincipal()).setRealUser(null);
		}
		FlexContext.getFlexClient().setAttribute("user", account);
		return new OutboundUser(user, null);
	}


	public String retrieveNonce()
	{
		FlexClient client = FlexContext.getFlexClient();
		return client != null ? client.getId() : String.valueOf(System.currentTimeMillis());
	}

	public boolean userLogout(String account)
	{
		FlexContext.getFlexClient().removeAttribute("user");
		if(loginManager != null)
		{
			loginManager.logout();
		}
		return true;
	}

	public Object createItem(@TypeDefination(type=Map.class, fieldNames=
	    {"account", "password", "name", "email"}) Object item)
	{
		if(!(item instanceof Map))
		{
			return null;
		}
		Map values = (Map)item;
		Object raw;
		String account = (raw = values.get("account")) == null ? null : String.valueOf(raw);
		String password = (raw = values.get("password")) == null ? null : String.valueOf(raw);
		String name = (raw = values.get("name")) == null ? null : String.valueOf(raw);
		String email = (raw = values.get("email")) == null ? null : String.valueOf(raw);
		return register(account, password, name, email);
	}
	
	/**
	 * register a new user account
	 * @deprecated please use createItem method
	 */
	public OutboundUser register(String account, String password, String name,  String email)
	{
		User user = new User();
    	user.setAccount(account);
    	user.setPassword(password);
    	user.setName(name);
    	user.setEmail(email);
    	user.setProfileImage(ContextUtil.getServerRootPath() +"/" + defaultProfileImage);
		Object result =  userDAO.saveObject(user);
		return result == null ? null : new OutboundUser((User)result, null);
		//getMemcachedClient().set(MemcachedClient.ID_USER_DB + account,  db);
	}

	public boolean deleteItem(String[] ids)
	{
		// TODO Auto-generated method stub
		return false;
	}

	public OutboundUser getItem(String id)
	{
		User user = getUser(id);
		return user == null ? null : new OutboundUser(user, null);
	}
	
	
	public User getUser(String id)
	{
		IDatasourceDistribute ds = getDatasourceDistribute();
		String old = ds.currentDatasource();
		ds.lookupDatasource(id, true);
		Object result =  userDAO.getObject(id);
		ds.useDatasouce(old);
		return result == null ? null : (User)result;
	}

	public List getItems(int index, int maxCount, Map condition)
	{
		// TODO Auto-generated method stub
		return null;
	}

	public ListResult getItemsWithTotal(int index, int maxCount, Map condition)
	{
		// TODO Auto-generated method stub
		return null;
	}
	
	public List<String> getAroundUserNames(String user, Map condition)
	{
		int showReply = -1;
		if(condition != null)
		{
			Object raw = condition.get("MessageSelector#showReplyMessage");
			if(raw instanceof Boolean)
			{
				showReply = (Boolean)raw ? 1 : 0;
			}
		}
		User centerUser = getUser(user);
		if(centerUser == null || !centerUser.isLocated())
		{
			return null;
		}
		int distance = centerUser.getRadius(); 
		String old = getDatasourceDistribute().currentDatasource();
		List list = null;
		try
		{
			Method method = userDAO.getClass().getMethod("getAroundUserNames", String.class, int.class, int.class);
			MethodInfo info = new MethodInfo(userDAO, method, user, distance, showReply);
			list = getDatasourceDistribute().executeOn(info, null, false);
		}
		catch(Exception e)
		{			
		}
		getDatasourceDistribute().useDatasouce(old);
		return ArrayUtil.union(list);
	}
	
	public List<OutboundUser> getUsers(List userNames)
	{
		if(userNames == null)
		{
			return null;
		}
		int index = userNames.size() - 1;
		List list = new ArrayList();
		OutboundUser user;
		while(index >= 0)
		{
			user = getItem(String.valueOf(userNames.get(index)));
			if(user != null)
			{
				list.add(user);
			}
			index--;
		}
		return list;
	}
	
	public List<String> getAroundAttentionedUserNames(String user, Map condition)
	{
		int showReply = -1;
		if(condition != null)
		{
			Object raw = condition.get("MessageSelector#showReplyMessage");
			if(raw instanceof Boolean)
			{
				showReply = (Boolean)raw ? 1 : 0;
			}
		}
		User centerUser = getUser(user);
		if(centerUser == null || !centerUser.isLocated())
		{
			return null;
		}
		String old = getDatasourceDistribute().currentDatasource();
		List list = null;
		try
		{
			Method method = userDAO.getClass().getMethod("getAroundAttentionedUserNames", String.class, int.class);
			MethodInfo info = new MethodInfo(userDAO, method, user, showReply);
			list = getDatasourceDistribute().executeOn(info, null, false);
		}
		catch(Exception e)
		{			
		}
		getDatasourceDistribute().useDatasouce(old);
		return ArrayUtil.union(list);
	}

	public User updateItem(String user, Map updateMap)
	{
		return userDAO.updateUser(user, updateMap);
	}
	
	public Map<String, Object> retrieveUserDetail(String account)
	{
		if(getUser() != null)
		{
			return null;
		}
		User user = getUser(account);
		String servermd5 = null;
		Map<String, Object> map = new HashMap<String, Object>();
		if(user != null)
		{
			servermd5 = user.getPassword() + FlexContext.getFlexClient().getId();
			try
			{
				MessageDigest md = MessageDigest.getInstance("MD5");
				md.update(servermd5.getBytes());
				servermd5 = new BigInteger(1, md.digest()).toString(16);
				int deltaLength = 32 - servermd5.length();
				servermd5 = String.valueOf(deltaLength  * 10).substring(1) + servermd5;
			} 
			catch (NoSuchAlgorithmException e)
			{
			}
		}
		map.put("credentials", servermd5);
		map.put("user", user);
		return map;
	}

}
